﻿using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel.Web;
using System.Web;
using System.Web.Security;
using System.Web.Script.Serialization;
using ESN.Models;
using ESN.Helpers;
using System.Linq.Expressions;

namespace ESN
{
    [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
    public class CoreService : DataService<ESNCoreDbContext>
    {
        // This method is called only once to initialize service-wide policies.
        public static void InitializeService(DataServiceConfiguration config)
        {
            //config.SetEntitySetPageSize("*", 20);
            config.SetEntitySetAccessRule("*", EntitySetRights.All);

            config.SetEntitySetAccessRule("Apps", EntitySetRights.None);
            config.SetEntitySetAccessRule("AppToken", EntitySetRights.None);

            config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
        }

        //UserWall
        [QueryInterceptor("UserWalls")]
        public Expression<Func<UserWall, bool>> OnQueryUserWalls()
        {
            return w => false;
        }
        [ChangeInterceptor("UserWalls")]
        public void OnChangeUserWalls(UserWall wall, UpdateOperations operations)
        {
            if (operations == UpdateOperations.Add)
            {
                if (!PermissionHelper.postWall(wall.UserId))
                {
                    throw new DataServiceException(400, "You donot have permission to post at my wall.");
                }
                wall.WTime = DateTime.Now;
            }
            else if (operations == UpdateOperations.Change)
            {
                throw new DataServiceException(400, "No change, delete only");
            }
            else if (operations == UpdateOperations.Delete)
            {
                throw new DataServiceException(400, "You can delete you post here!");
            }
        }
        [WebGet]
        public IQueryable<UserWall> GetUserWall(string name)
        {
            var user = Membership.GetUser(name);
            if (user == null)
                throw new DataServiceException(404, "User not found");
            if (PermissionHelper.readWall((Guid)user.ProviderUserKey))
                return CurrentDataSource.UserWalls.Where(w => w.UserId == (Guid)user.ProviderUserKey);
            else
                throw new DataServiceException(403, "You arenot allow to read my wall!");
        }
        [WebGet]
        public int DeleteWall(int WId)
        {
            var wall = CurrentDataSource.UserWalls.Find(WId);
            if (wall != null && PermissionHelper.IsOwner(wall.WriterId))
            {
                CurrentDataSource.UserWalls.Remove(wall);
                return 1;
            }
            return 0;
        }

        //UserNotice
        [QueryInterceptor("UserNotices")]
        public Expression<Func<UserNotice, bool>> OnQueryUserNotices()
        {
            return w => false;
        }
        [ChangeInterceptor("UserNotices")]
        public void OnChangeUserNotices(UserNotice notice, UpdateOperations operations)
        {
            Guid id = new Guid();
            if (!PermissionHelper.IsAuthenticated(ref id))
            {
                throw new DataServiceException(401, "your are not logged on!");
            }

            if (operations == UpdateOperations.Change)
            {
                throw new DataServiceException(405, "Can change!");
            }
            else if (operations == UpdateOperations.Delete)
            {
                if (notice.UserId != id)
                    throw new DataServiceException(400, "How can you delete something not belong to you?");
            }
            else if (operations == UpdateOperations.Add)
            {
                notice.SenderId = id;
            }
        }
        [WebGet]
        public IQueryable<UserNotice> GetUserNotice()
        {
            Guid id = new Guid();
            if (!PermissionHelper.IsAuthenticated(ref id))
                throw new DataServiceException(401, "You must login to read you notice!");

            return CurrentDataSource.UserNotices.Where(n => (n.NNew) && (n.UserId == id));
        }
        [WebGet]
        public int CountUserNotice()
        {
            Guid id = new Guid();
            if (!PermissionHelper.IsAuthenticated(ref id))
                throw new DataServiceException(401, "You must login to read you notice!");

            return CurrentDataSource.UserNotices.Where(n => (n.NNew) && (n.UserId == id)).Count();
        }
        //FriendRequest
        [QueryInterceptor("FriendRequests")]
        public Expression<Func<FriendRequest, bool>> OnQueryFriendRequests()
        {
            return w => false;
        }
        [ChangeInterceptor("FriendRequests")]
        public void OnChangeFriendRequests(FriendRequest r, UpdateOperations operations)
        {
            if (operations == UpdateOperations.Add)
            {
                Guid id = new Guid();
                if (PermissionHelper.IsAuthenticated(ref id))
                {
                    r.UserId = id;
                    r.FRTime = DateTime.Now;
                }
                else
                {
                    throw new DataServiceException(401, "Why don't you logged in?");
                }
            }
            else if (operations == UpdateOperations.Change)
            {
                throw new DataServiceException(400, "No change, delete only");
            }
            else if (operations == UpdateOperations.Delete)
            {
                throw new DataServiceException(400, "You can delete you post here!");
            }
        }
        [WebGet]
        public IQueryable<FriendRequest> GetFriendRequest()
        {
            Guid id = new Guid();
            if (!PermissionHelper.IsAuthenticated(ref id))
                throw new DataServiceException(401, "You must login to read you notice!");

            return CurrentDataSource.FriendRequests.Where(r => r.FriendId == id);
        }
        [WebGet]
        public bool AcceptFriendRequest(int r)
        {
            var request = CurrentDataSource.FriendRequests.Find(r);
            if (request == null)
                return false;
            if (!PermissionHelper.IsOwner(request.FriendId))
                return false;

            var user = CurrentDataSource.Profiles.Find(request.UserId);
            var friend = CurrentDataSource.Profiles.Find(request.FriendId);

            if (user == null || friend == null)
                return false;

            user.Friends.Add(friend);
            friend.Friends.Add(user);

            CurrentDataSource.FriendRequests.Remove(request);

            UserNotice n = new UserNotice();
            n.NContent = "<a href=\"/"+ friend.UserName +"/Home\">"+ friend.DisplayName +"</a>" + "has accept your request";
            n.NAbout = "friendrequest|accepted|" + friend.UserId;
            n.NNew = true;
            n.UserId = user.UserId;

            CurrentDataSource.UserNotices.Add(n);

            CurrentDataSource.SaveChanges();

            return true;
        }
        [WebGet]
        public bool RejectFriendRequest(int r)
        {
            var request = CurrentDataSource.FriendRequests.Find(r);
            if (request == null)
                return false;
            if (!PermissionHelper.IsOwner(request.FriendId))
                return false;

            CurrentDataSource.FriendRequests.Remove(request);
            var fr = request.Friend;
            UserNotice n = new UserNotice();
            n.NContent = "<a href=\"/" + fr.UserName + "/Home\">" + fr.DisplayName + "</a>" + "has reject your request";
            n.NAbout = "friendrequest|accepted|" + request.FriendId;
            n.NNew = true;
            n.UserId = request.UserId;

            CurrentDataSource.UserNotices.Add(n);

            CurrentDataSource.SaveChanges();
            return true;
        }
        //Group wall
        [WebGet]
        public IQueryable<GroupWall> GetGroupWall(int gid)
        {
            var group = CurrentDataSource.Groups.Find(gid);
            if (group == null)
                throw new DataServiceException(404, "User not found");
            if (PermissionHelper.readWall(group.GId))
                return CurrentDataSource.GroupWalls.Where(w => w.GId == gid);
            else
                throw new DataServiceException(403, "You arenot allow to read my wall!");
        }

        [QueryInterceptor("GroupRequests")]
        public Expression<Func<GroupRequest, bool>> OnQueryGroupRequests()
        {
            return w => false;
        }
        [ChangeInterceptor("GroupRequests")]
        public void OnChangeGroupRequests(GroupRequest r, UpdateOperations operations)
        {
            if (operations == UpdateOperations.Add)
            {
                Guid id = new Guid();
                if (PermissionHelper.IsAuthenticated(ref id))
                {
                    r.UserId = id;
                    r.GRTime = DateTime.Now;
                }
                else
                {
                    throw new DataServiceException(401, "Why don't you logged in?");
                }
            }
            else if (operations == UpdateOperations.Change)
            {
                throw new DataServiceException(400, "No change, delete only");
            }
            else if (operations == UpdateOperations.Delete)
            {
                throw new DataServiceException(400, "You can delete you post here!");
            }
        }
        [WebGet]
        public IQueryable<GroupRequest> GetMemberRequests(int id)
        {
            if (!PermissionHelper.IsOwner(id))
                throw new DataServiceException(400, "You don't have permission to view this!");

            return CurrentDataSource.GroupRequests.Where(r => r.GId == id);
        }
        [WebGet]
        public bool AcceptMemberRequest(int r)
        {
            var request = CurrentDataSource.GroupRequests.Find(r);
            if (request == null)
                return false;
            if (!PermissionHelper.IsOwner(request.GId))
                return false;
            var user = CurrentDataSource.Profiles.Find(request.UserId);
            var group = CurrentDataSource.Groups.Find(request.GId);

            if (user == null || group == null)
                return false;

            group.Members.Add(user);

            UserNotice n = new UserNotice();
            n.NContent = "<a href='/Group/Home/"+ group.GId+"'>" + group.GName + "</a>" + "has accept your request";
            n.NAbout = "friendrequest|accepted|" + group.GId;
            n.NNew = true;
            n.UserId = user.UserId;

            CurrentDataSource.UserNotices.Add(n);
            CurrentDataSource.GroupRequests.Remove(request);
            CurrentDataSource.SaveChanges();
            return true;
        }
        [WebGet]
        public bool RejectMemberRequest(int r)
        {
            var request = CurrentDataSource.GroupRequests.Find(r);
            if (request == null)
                return false;
            if (!PermissionHelper.IsOwner(request.GId))
                return false;

            CurrentDataSource.GroupRequests.Remove(request);
            var fr = request.Groups;
            UserNotice n = new UserNotice();
            n.NContent = "<a href='/Group/Home/"+fr.GId+"'>" + fr.GName + "</a>" + " has reject your request";
            n.NAbout = "friendrequest|accepted|" + request.GId;
            n.NNew = true;
            n.UserId = request.UserId;

            CurrentDataSource.UserNotices.Add(n);

            CurrentDataSource.SaveChanges();
            return true;
        }
        [WebGet]
        public IEnumerable<CustomProfile> GetFriendList(Guid id, int skip)
        {
            return CurrentDataSource.Profiles.Find(id).Friends.Take(20).Skip(skip);
        }
        [WebGet]
        public IEnumerable<CustomProfile> GetMemberList(int id, int skip)
        {
            return CurrentDataSource.Groups.Find(id).Members.Take(20).Skip(skip);
        }
        [WebGet]
        public IEnumerable<CustomProfile> AutocompleteFriend(string start)
        {
            Guid id = new Guid();
            if (!PermissionHelper.IsAuthenticated(ref id))
                throw new DataServiceException(401, "You must logged in");

            var user = CurrentDataSource.Profiles.Find(id);
            return user.Friends.Where(f => f.DisplayName.IndexOf(start) > -1).Take(5);
        }
        [WebGet]
        public IEnumerable<Group> AutocompleteGroup(string start)
        {
            Guid id = new Guid();
            if (!PermissionHelper.IsAuthenticated(ref id))
                throw new DataServiceException(401, "You must logged in");

            var user = CurrentDataSource.Profiles.Find(id);
            var owned = CurrentDataSource.Groups.Where(g => g.OwnerId == id && g.GName.IndexOf(start) > -1).Take(5);
            return user.Groups.Where(g => g.GName.IndexOf(start) > -1).Take(5).Concat(owned);
        }
        [WebGet]
        public bool SetAlbumCover(int id)
        {
            var piz = CurrentDataSource.Attachments.Find(id);
            if (piz != null)
            {
                piz.Parent.FThumb = piz.ASource;
            }
            CurrentDataSource.SaveChanges();
            return true;
        }
        [WebGet]
        public bool DeleteAttchment(int id)
        {
            var att = CurrentDataSource.Attachments.Find(id);
            try
            {
                RemoteHelper.Delete("https://apis.live.net/v5.0/" + att.AKey + "?access_token=" + CurrentDataSource.AppToken.Find(1).access_token);
            }
            catch
            {
                throw new DataServiceException(500, "there was an error");
            }
            CurrentDataSource.Attachments.Remove(att);
            CurrentDataSource.SaveChanges();
            return true;
        }
    }
}
